package com.orange.lockscreen.server;

import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

import com.android.internal.policy.impl.ExtLockScreenLoader.ExtLockScreen;
import com.orange.lockscreen.R;
import com.orange.lockscreen.SlatHashMap;
import com.orange.lockscreen.common.Constants;
import com.orange.lockscreen.common.Constants.LSWidget_Type;
import com.orange.lockscreen.common.Constants.Slat_Type;
import com.orange.lockscreen.common.Constants.Slider_Msg;
import com.orange.lockscreen.common.Constants.Wallpaper_Provider;
import com.orange.lockscreen.common.LockScreenPreferences;
import com.orange.lockscreen.common.LockScreenUtils;
import com.orange.lockscreen.common.LogHelper;
import com.orange.lockscreen.layers.finger.SwipePanel;
import com.orange.lockscreen.layers.finger.TapPanel;
import com.orange.lockscreen.layers.slider.SliderSlatPanel;
import com.orange.lockscreen.layers.tip.TipSlatPanel;
import com.orange.lockscreen.layers.widget.WidgetSlat;
import com.orange.lockscreen.layers.widget.WidgetSlatPanel;
import com.orange.lockscreen.nativeView.TimeDateView;

/**
 * 
 * LockscreenView: can be instanced to replace default lockscreen view.
 * 
 */
public class LockscreenView extends ExtLockScreen implements Slider_Msg,
		Slat_Type, LSWidget_Type, OnCompletionListener {

	private static final String		TAG				= "LockscreenView";

	private static final int		SLAT_COUNT		= 4;
	private static final int		LS_TIMEOUT		= 8 * 1000;
	private static final int		LS_LONG_TIMEOUT	= 30 * 60 * 1000;

	private static final int[]		S_BACKGROUNDS	= {
			R.drawable.wallpaper_bubbles, R.drawable.wallpaper_circles,
			R.drawable.wallpaper_stripes, R.drawable.wallpaper_candles,
			R.drawable.wallpaper_3d_lights		};

	private boolean					mIsUnLock		= false;
	private boolean					mIsEventUnlock	= false;
	private boolean					mIsMusicUnlock	= false;

	private int						mIndexOfBG		= 0;

	private Bitmap					mSliderBitmap	= null;

	private MediaPlayer				mediaPlayer		= null;
	// private Vibrator mVibrator = null;
	private AudioManager			mAudioManager	= null;

	private WidgetSlatPanel			mWidgetLayer;
	private SliderSlatPanel			mSliderLayer;
	private SwipePanel				mSwipeLayer;
	private TapPanel				mTaplayer;
	private TipSlatPanel			mTipLayer;

	private RelativeLayout			mRootLayout;
	private LCMessageHandler		mHandler;
	private LockscreenCallback		mLockscreenCallback;
	private TimeDateViewCallback	mTimeDateViewCallback;

	private Context					mContext;
	
    // last known plugged in state
    private boolean mPluggedIn = false;

	public LockscreenView(Context context, LockscreenCallback callback) {
		super(context);
		mLockscreenCallback = callback;
		onCreate(context);
	}

	/**
	 * 
	 * Init root view, Lockscreen layers and TimeDate view.
	 * 
	 * @param context
	 */
	private void onCreate(final Context context) {
		mContext = context;

		LockScreenUtils.LockscreenViewSize vs = LockScreenUtils.getScreenRealSize(context);
		SlatHashMap.init(SLAT_COUNT, vs.realHeight,vs.realWidth);
		// initialize SlatHashMap
//		SlatHashMap.init(SLAT_COUNT, LockScreenUtils.getScreenHeight(context),
//				LockScreenUtils.getScreenWidth(context));

		// init root view
		mRootLayout = new RelativeLayout(context);
		LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.FILL_PARENT);
		mRootLayout.setLayoutParams(params);
		addView(mRootLayout);

		mHandler = new LCMessageHandler();

		LogHelper.i(TAG, "onCreate. Lockscreen startup.");

		init(context);
		
		// Only use the isDevicePluggedIn() onCreate.
		mPluggedIn = isDevicePluggedIn();
		LogHelper.i(TAG, "onCreate. Lockscreen startup. mPluggedIn=" + mPluggedIn);

		mHandler.post(new Runnable() {

			@Override
			public void run() {
				if (null != mWidgetLayer) {
					boolean isDevicePluggedIn = mPluggedIn;
					mBatteryLevel = getBatteryLevel();
					TimeDateView timeDateView = new TimeDateView(mContext,
							isDevicePluggedIn, mBatteryLevel);

					mWidgetLayer.addNativeView(timeDateView);
					setTimeDateViewCallback(timeDateView);
					
					LogHelper.d(TAG, "onCreate. mPluggedIn=" + mPluggedIn);
					// comment by gaoge ,this init battery won't operate needn't
					// invoke
					updateBatteryLevel();
				}
			}
		});
	}

	 private void updateBatteryLevel(){
		 mContext.registerReceiver(mBatteryInfoInitReceiver, new
		 IntentFilter(Intent.ACTION_BATTERY_CHANGED));
		 mContext.unregisterReceiver(mBatteryInfoInitReceiver);
	 }

	int	mBatteryLevel;

	 private BroadcastReceiver mBatteryInfoInitReceiver = new BroadcastReceiver(){
	 @Override
	 public void onReceive(Context context, Intent intent) {
			if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
				int level = intent.getIntExtra("level", 0);
				int scale = intent.getIntExtra("scale", 100);
				boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
				mPluggedIn = batteryCharging;
				
				LogHelper.d(TAG, "## battery Init: level : " + level
						+ " ,scale: " + scale
						+ " ,mPluggedIn: " + mPluggedIn
						);
				if (null != mTimeDateViewCallback) {
					mBatteryLevel = level * 100 / scale;

					if (LogHelper.enableDefaultLog) {
						LogHelper.d(TAG,
								"$$$$$$$$$$$$$$$$$$$$$$$$$$$$mReceiver, null != mTimeDateViewCallback "
										+ (null != mTimeDateViewCallback)
										+ ",mBatteryLevel" + mBatteryLevel
										+ ",null != mTimeDateViewCallback "
										+ (null != mTimeDateViewCallback));
					}
			
			refreshBatteryInfoView();
		}
	
		 }
	 }
	 };

	private void refreshBatteryInfoView() {
		if (null != mTimeDateViewCallback) {
			final boolean isDevicePluggedIn = mPluggedIn;
			mHandler.post(new Runnable() {
				@Override
				public void run() {
					mTimeDateViewCallback.onBatteryChangedOuter(
							isDevicePluggedIn, mBatteryLevel);
				}
			});

		}
	}

	private void init(Context context) {
		initLayers(context);
		initBackgroundWallpaper();
		initMediaPlayer(context);
		// initVibrator(context);
		initWidgetLayerPanelGrid();
	}

	/**
	 * 
	 * Create WidgetSlatPanel, SliderSlatPanel, SwipePanel TapPanel,
	 * TipSlatPanel; and add them into root view.
	 * 
	 * @param context
	 */
	private void initLayers(final Context context) {
		final RelativeLayout rootLayout = mRootLayout;

		// init the 1st layer
		mWidgetLayer = new WidgetSlatPanel(context);
		mWidgetLayer.init(mHandler);
		rootLayout.addView(mWidgetLayer);

		// init the 2nd layer
		mSliderLayer = new SliderSlatPanel(context);
		mSliderLayer.init(mHandler);
		rootLayout.addView(mSliderLayer);
		mSliderLayer.setWidgetLayer(mWidgetLayer);

		// init the 3rd layer
		mSwipeLayer = new SwipePanel(context);
		mSwipeLayer.init(mHandler);
		rootLayout.addView(mSwipeLayer);

		// init the 4th layer
		mTaplayer = new TapPanel(context);
		mTaplayer.init(mHandler);
		rootLayout.addView(mTaplayer);

		// init the 5th layer
		mTipLayer = new TipSlatPanel(context);
		mTipLayer.init(mHandler);
		rootLayout.addView(mTipLayer);
	}

	/**
	 * Init background bitmap for Lockscreen. If share wallpaper with
	 * homescreen, use transparent bitmap; Or if use wallpaper from gallery, get
	 * bitmap from DB; Or use Lockscreen wallpaper.
	 */
	private void initBackgroundWallpaper() {
		Bitmap temp = null;
		mIndexOfBG = LockScreenPreferences.getIndexOfBG();
		if (LockScreenPreferences.isWallpaperFromHomescreen()) {
			temp = BitmapFactory.decodeResource(getResources(),
					R.drawable.wallpaper_transparent);
		} else {
			if (LockScreenPreferences.isWallpaperFromGallery()) {
				Cursor cursor = getContext().getContentResolver().query(
						Wallpaper_Provider.WALLPAPER_URI, null, null, null,
						null);
				if (cursor != null) {
					if (cursor.moveToFirst()) {
						int index = cursor
								.getColumnIndex(Wallpaper_Provider.COLUMN_WALLPAPER_PICTURE);
						byte[] buffer = cursor.getBlob(index);
						temp = BitmapFactory.decodeByteArray(buffer, 0,
								buffer.length);
					} else {
						temp = BitmapFactory.decodeResource(getResources(),
								S_BACKGROUNDS[mIndexOfBG]);
					}
					cursor.close();
				} else {
					temp = BitmapFactory.decodeResource(getResources(),
							S_BACKGROUNDS[mIndexOfBG]);
				}
			} else {
				temp = BitmapFactory.decodeResource(getResources(),
						S_BACKGROUNDS[mIndexOfBG]);
			}
		}
		if (temp != null) {
			mSliderBitmap = LockScreenUtils.spliteSlideBitmap(temp,
					SlatHashMap.MUSIC_WIDGET_ROWINDEX);
			Bitmap bgBitmap = LockScreenUtils.spliteBackground(temp);
			mRootLayout.setBackgroundDrawable(new BitmapDrawable(bgBitmap));
		}
	}

	/**
	 * 
	 * Initialize MediaPlayer for lock/unlock sound.
	 * 
	 * @param context
	 */
	private void initMediaPlayer(Context context) {
		try {
			if (null == mAudioManager) {
				mAudioManager = (AudioManager) context
						.getSystemService(Activity.AUDIO_SERVICE);
			}
			if (null == mediaPlayer) {
				// setVolumeControlStream(AudioManager.STREAM_NOTIFICATION);
				mediaPlayer = MediaPlayer.create(context, R.raw.clickon);
				mediaPlayer.setLooping(false);
				mediaPlayer.setVolume(0.5f, 0.5f);
				mediaPlayer.setOnCompletionListener(this);
				
				// Why should play on start. -20120215
//				if (LockScreenPreferences.isUnlockSoundEnabled()) {
//					int mode = mAudioManager.getRingerMode();
//					if (mode == AudioManager.RINGER_MODE_NORMAL) {
//						mediaPlayer.start();
//					}
//				}
			}
		} catch (Exception e) {
			LogHelper.e(TAG, "initMediaPlayer. ", e);
		}
	}

	/**
	 * 
	 * Keep TimeDateView callback for monitoring battery change or time tick.
	 * 
	 * @param c
	 *            TimeDateViewCallback
	 */
	private void setTimeDateViewCallback(TimeDateViewCallback c) {
		mTimeDateViewCallback = c;
	}

	@Override
	public void onCompletion(MediaPlayer mp) {
		if (mIsUnLock) {
			close();
		}
	}

	/**
	 * Play lock/unlock sound or close directly by settings.
	 */
	private void playOpenMusicOrClose() {
		// add by gaoge 2011-08-27 for fix acer crash bug
		int mode = AudioManager.RINGER_MODE_NORMAL;
		if (LockScreenPreferences.isUnlockSoundEnabled()) {
			if (null != mAudioManager) {
				mode = mAudioManager.getRingerMode();
			}

			if (mode == AudioManager.RINGER_MODE_NORMAL) {
				if (null != mediaPlayer) {
					mediaPlayer.start();
				}
			} else {
				onCompletion(null);
			}
		} else {
			close();
		}
	}

	/**
	 * Release mediaplayer object.
	 */
	private void releaseMediaPlayer() {
		if (null != mediaPlayer) {
			mediaPlayer.release();
			mediaPlayer = null;
		}
	}

	// private void initVibrator(Context context) {
	// if (null == mVibrator) {
	// mVibrator = (Vibrator) context
	// .getSystemService(Activity.VIBRATOR_SERVICE);
	// }
	// }
	//
	// private void releaseVibrator() {
	// if (null != mVibrator) {
	// mVibrator = null;
	// }
	// }

	// private void vibrateCellPhone() {
	// if (null != mVibrator) {
	// mVibrator.vibrate(30);
	// }
	// }

	/**
	 * Exit Lockscreen and go to UnlockScreen.
	 */
	private void close() {
		this.goToUnlockScreen();

		if (null != mContext) {
			if (mIsEventUnlock) {
				LockScreenUtils.sendBroadcast(mContext,
						Constants.ACTION_EVENT_UNLOCK);
			} else if (mIsMusicUnlock
					|| (null != mSliderLayer && mSliderLayer.isMusicDocked())) {
				LockScreenUtils.sendBroadcast(mContext,
						Constants.ACTION_MUSIC_UNLOCK);
			}
		}

		if (null != mLockscreenCallback) {
			mLockscreenCallback.unLock();
		}
	}

	/**
	 * Rollback music slat when it's opened.
	 */
	private void rollbackMusicSlat() {
		if (null != mSliderLayer) {
			mSliderLayer.rollbackMusicSlat();
		}
	}

	/**
	 * Handler events from SliderSlatPanel, WidgetSlatPanel.
	 */
	private class LCMessageHandler extends Handler {
		@Override
		public void handleMessage(final Message msg) {
			int rowIndex = msg.arg1;
			// Log.e(TAG, msgIdToString(msg.what) + ", row=" + rowIndex);
			LogHelper.d(
					TAG,
					"handleMessage. message.what: 0x"
							+ Integer.toHexString(msg.what));
			switch (msg.what) {
			case MSG_SLIDER_SELECTED: // 0x1000
				doWorkOnSliderSelected(rowIndex);
				break;
			case MSG_SLIDER_VISBLE: // 0x1004
				doWorkOnSliderVisble(rowIndex);
				break;
			case MSG_SLIDER_CLOSED: // 0x1002
				doWorkOnSliderClosed(rowIndex);
				break;
			case MSG_SLIDER_OPENED: // 0x1001
				doWorkOnSliderOpened(rowIndex);
				break;
			case MSG_SLIDER_DOUBLE_TAP: // 0x1008
				doWorkOnSliderDoubleTap(rowIndex);
				break;
			case MSG_SLIDER_SINGLE_TAP: // 0x1007
				doWorkOnSliderSingleTap(rowIndex, (MotionEvent) msg.obj);
				break;
			case MSG_SLIDER_HIT_BROAD: // 0x1003
				doWorkOnsliderHitBroad(rowIndex);
				break;
			case MSG_SLIDER_CATCH_ON: // 0x1005
			case MSG_SLIDER_CATCH_OFF: // 0x1006
				LockscreenView.this.pokeWakeLock(LS_TIMEOUT);
				break;
			case MSG_CONTROL_LONG_CATCH_ON: // 0x2000
				LockscreenView.this.pokeWakeLock(LS_LONG_TIMEOUT);
				break;
			case MSG_CONTROL_LONG_CATCH_OFF: // 0x2001
				LockscreenView.this.pokeWakeLock(LS_TIMEOUT);
				break;
			case MSG_SLIDER_SIMPLE_DOWN: // 0x1009
				doWorkOnSliderSimpleDown(rowIndex);
				break;
			case MSG_SLIDER_SWIPE: // 0x1010
				doWorkOnSliderSwipe(rowIndex);
				break;
			case MSG_SLIDER_MOVING: // 0x1011
				int xOffset = msg.arg2;
				doWorkOnSliderMoving(rowIndex, xOffset);
				break;
			default:
				break;
			}
		}
	}

	// private String msgIdToString(int what) {
	// String msg = "";
	// switch (what) {
	// case MSG_SLIDER_SELECTED:
	// msg = "MSG_SLIDER_SELECTED";
	// break;
	// case MSG_SLIDER_VISBLE:
	// msg = "MSG_SLIDER_VISBLE";
	// break;
	// case MSG_SLIDER_CLOSED:
	// msg = "MSG_SLIDER_CLOSED";
	// break;
	// case MSG_SLIDER_OPENED:
	// msg = "MSG_SLIDER_OPENED";
	// break;
	// case MSG_SLIDER_DOUBLE_TAP:
	// msg = "MSG_SLIDER_DOUBLE_TAP";
	// break;
	// case MSG_SLIDER_SINGLE_TAP:
	// msg = "MSG_SLIDER_SINGLE_TAP";
	// break;
	// case MSG_SLIDER_HIT_BROAD:
	// msg = "MSG_SLIDER_HIT_BROAD";
	// break;
	// case MSG_SLIDER_CATCH_ON:
	// msg = "MSG_SLIDER_CATCH_ON";
	// break;
	// case MSG_SLIDER_CATCH_OFF:
	// msg = "MSG_SLIDER_CATCH_OFF";
	// break;
	// case MSG_SLIDER_SIMPLE_DOWN:
	// msg = "MSG_SLIDER_SIMPLE_DOWN";
	// break;
	// case MSG_SLIDER_SWIPE:
	// msg = "MSG_SLIDER_SIMPLE_DOWN";
	// break;
	// default:
	// break;
	// }
	// return msg;
	// }

	/**
	 * Do works when sliderslat is selected.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderSelected(int rowIndex) {
		Bitmap wsBitmap = mWidgetLayer.getSlatDrawCache(rowIndex); // music
		if (wsBitmap != null && mSliderBitmap != null) {
			Bitmap bitmap = LockScreenUtils.combineBitmaps(mSliderBitmap,
					wsBitmap);
			if (null != bitmap) {
				mSliderLayer.setSliderSlatBackground(rowIndex, bitmap);
			}
		}
	}

	/**
	 * Do works when sliderslat is visble.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderVisble(int rowIndex) {
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_MOVABLE:
			mWidgetLayer.setMusicSlatState(true);
			mSliderLayer.setSliderSlatVisible(rowIndex);
			mWidgetLayer.layoutWidgetSlat(rowIndex, 0);
			mWidgetLayer.changeSlatState(rowIndex, WidgetSlat.STATE_COVERED);
			sendMusicSlatBroadcast(Constants.ACTION_MUSIC_SLAT_OPENED);
			break;
		default:
			break;
		}
	}

	/**
	 * Do works when sliderslat is closed.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderClosed(int rowIndex) {
		if (null != mSliderLayer && mSliderLayer.isTracking()) {
			return;
		}
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_MOVABLE:
			mWidgetLayer.changeSlatState(rowIndex, WidgetSlat.STATE_NO_COVERED);
			mWidgetLayer.setMusicSlatState(false);
			mWidgetLayer.layoutWidgetSlat(rowIndex, -1);
			mSliderLayer.setSliderSlatInvisible(rowIndex);
			mSliderLayer.setSliderSlatAnimaionEnd(rowIndex);
			sendMusicSlatBroadcast(Constants.ACTION_MUSIC_SLAT_CLOSED);
			break;
		case TYPE_FIXED_NO_CONTENT:
			if (isHeadsetRollback) {
				isHeadsetRollback = false;
				mWidgetLayer.changeSlatState(rowIndex,
						WidgetSlat.STATE_NO_COVERED);
				mWidgetLayer.setMusicSlatState(false);
				mWidgetLayer.layoutWidgetSlat(rowIndex, -1);
				mSliderLayer.setSliderSlatInvisible(rowIndex);
				mSliderLayer.setSliderSlatAnimaionEnd(rowIndex);
				mWidgetLayer.invalidateWidgetSlat(rowIndex);
				sendMusicSlatBroadcast(Constants.ACTION_MUSIC_SLAT_CLOSED);
			}
			break;
		default:
			break;
		}
	}

	/**
	 * Send broadcast to music widget when slat is opened or closed.
	 * 
	 * @param action
	 *            OPEND/CLOSED ACTION
	 */
	private void sendMusicSlatBroadcast(String action) {
		Intent intent = new Intent();
		intent.setAction(action);
		
		try {
			mContext.sendBroadcast(intent);
		} catch (Exception e) {
			LogHelper.e(TAG, "sendBroadcast. ", e);
			// Should use "IllegalStateException", but trying to be safe.
		}
	}

	/**
	 * Do works when double tapping is involved.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderDoubleTap(int rowIndex) {
		boolean isShown = false;
		mIsEventUnlock = false;
		mIsUnLock = false;
		mIsMusicUnlock = false;
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_MOVABLE_UNLOCK:
			mIsEventUnlock = true;
		case TYPE_UNLOCK:
			mIsUnLock = true;
			isShown = true;
			break;
		case TYPE_MOVABLE:
			mIsMusicUnlock = true;
			mIsUnLock = true;
			isShown = true;
			break;
		default:
			break;
		}
		if (isShown) {
			mTaplayer.showOnDoubleTap();
			mTipLayer.hide();
			this.postDelayed(new Runnable() {
				@Override
				public void run() {
					// vibrateCellPhone();
					playOpenMusicOrClose();
				}
			}, 400);
		}
	}

	/**
	 * Do works when single tapping is involved.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderSingleTap(int rowIndex, MotionEvent event) {
		int type = SlatHashMap.getSlatType(rowIndex);
		int resId = 0;
		int delay = 500;
		boolean isShown = false;
		switch (type) {
		case TYPE_MOVABLE_UNLOCK:
			isShown = true;
			resId = getNotificationTipID();
			break;
		case TYPE_MOVABLE:
			if (mSliderLayer != null && !mSliderLayer.isMusicDocked()) {
				isShown = true;
				resId = R.string.tip_music;
			}
			break;
		case TYPE_UNLOCK:
			isShown = true;
			resId = R.string.tip_unlock;
			break;
		default:
			break;
		}
		if (isShown) {
			mTaplayer.showOnSingleTap((int) (event.getX()),
					(int) (event.getY()), rowIndex);
			if (LockScreenPreferences.isUnlockPromptEnabled()) {
				mTipLayer.show(rowIndex, resId, delay);
			}
		}
	}

	/**
	 * Do works when down event is involved.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderSimpleDown(int rowIndex) {
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_UNLOCK:
			if (mSwipeLayer != null) {
				// mFingerLayer.showCircle();
			}
			break;
		default:
			break;
		}
	}

	/**
	 * Do works when swipe event is involved.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderSwipe(int rowIndex) {
		int resId = 0;
		int delay = 0;
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_UNLOCK:
			resId = R.string.tip_unlock;
			delay = 400;
			if (mSwipeLayer != null) {
				mSwipeLayer.show();
			}
			break;
		case TYPE_MOVABLE_UNLOCK:
			resId = getNotificationTipID();
			break;
		default:
			break;
		}
		if (resId != 0 && mTipLayer != null
				&& LockScreenPreferences.isUnlockPromptEnabled()) {
			mTipLayer.show(rowIndex, resId, delay);
		}
	}

	/**
	 * Get prompt info string resource ID by event count and settings. modify by
	 * gaoge 2011-08-19,for fix bug 001239
	 * 
	 * @return Resource ID, or 0.
	 */
	private int getNotificationTipID() {
		int resId = 0;
		boolean isMultiEventType = false;

		// int SUMCOUNTINDEX = 0;
		// int UNREADMMSINDEX = 1;
		// int MISSCALLINDEX = 2;
		// int VOICEMAILINDEX = 3;

		int notZeroCnt = 0;

		List<Integer> cnt_list = LockScreenUtils.getNotificationCount(mContext);

		for (int i = 1; i < cnt_list.size(); i++) {
			int value = cnt_list.get(i);
			if (0 != value)
				notZeroCnt++;
		}
		if (notZeroCnt > 1)
			isMultiEventType = true;

		boolean isNtfcEnabled = LockScreenPreferences
				.isNotificationScreenEnabled();
		// boolean isNtfcExists = LockScreenUtils.isPackageExist(mContext,
		// Constants.PKG_NOTIFICATION_SUMMARY);
		boolean isNtfcExists = true;
		if (!isNtfcExists) {
			resId = R.string.tip_event_single;
		} else {
			if (!isNtfcEnabled) {
				resId = R.string.tip_event_single;
			} else {
				if (isMultiEventType) {
					resId = R.string.tip_event_multiple;
				} else {
					resId = R.string.tip_event_single;
				}
			}
		}

		return resId;
	}

	/**
	 * Do works when sliderslat is opened.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnSliderOpened(int rowIndex) {
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_MOVABLE:
			mWidgetLayer.setMusicSlatState(true);
			mSliderLayer.setSliderSlatAnimaionEnd(rowIndex);
			// vibrateCellPhone();
			break;
		default:
			break;
		}
	}

	/**
	 * Do works when sliderslat hit broad of screen.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 */
	private void doWorkOnsliderHitBroad(int rowIndex) {
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_MOVABLE:
		case TYPE_UNLOCK:
		case TYPE_MOVABLE_UNLOCK:
			// vibrateCellPhone();
			break;
		default:
			break;
		}
	}

	/**
	 * Do works when sliderslat is moving.
	 * 
	 * @param rowIndex
	 *            Row index of slat
	 * @param xOffset
	 *            distance of moving
	 */
	private void doWorkOnSliderMoving(int rowIndex, int xOffset) {
		int type = SlatHashMap.getSlatType(rowIndex);
		switch (type) {
		case TYPE_MOVABLE:
			mWidgetLayer.layoutWidgetSlat(rowIndex, xOffset);
			break;
		default:
			break;
		}
	}

	/**
	 * Add hostview into WidgetSlatPanel
	 * 
	 * @param hostView
	 *            hostview which contains widget
	 */
	void addWidgetView(LSWidgetHostView hostView) {
		if (null != mWidgetLayer) {
			mWidgetLayer.addWidgetView(hostView);
		}
	}

	/**
	 * Set widget slat moveable property.
	 * 
	 * @param type
	 *            widget type
	 * @param moveable
	 *            moveable or not
	 */
	void setWidgetMoveable(int type, boolean moveable) {
		int pos = SlatHashMap.getPosByWidgetViewType(type);
		if (pos > -1 && pos < 4) {
			if (moveable) {
				if (type == TYPE_EVENT) {
					SlatHashMap.setSlatType(pos, TYPE_MOVABLE_UNLOCK);
				}
				if (type == TYPE_MUSIC) {
					SlatHashMap.setSlatType(pos, TYPE_MOVABLE);
				}
			} else {
				SlatHashMap.setSlatType(pos, TYPE_FIXED_NO_CONTENT);
			}

			if (null != mWidgetLayer) {
				mWidgetLayer.invalidateWidgetSlat(pos);
			}
		}
	}

	/**
	 * 
	 * Init Widget layer to display panel grid lines as appropriate.
	 * 
	 */
	void initWidgetLayerPanelGrid() {
		if (null != mWidgetLayer) {
			mWidgetLayer
					.invalidateWidgetSlat(SlatHashMap.Event_WIDGET_ROWINDEX);
		}
	}

//	/**
//	 * Add TimeDateView into WidgetSlatPanel.
//	 * 
//	 * @param nativeView
//	 *            TimeDateView object
//	 */
//	void addNativeWidgetView(View nativeView) {
//		if (null != mWidgetLayer) {
//			mWidgetLayer.addNativeView(nativeView);
//		}
//	}

	@Override
	public void cleanUp() {
		super.cleanUp();
		LogHelper.v(TAG, "cleanUp. ");

		if (null != mLockscreenCallback) {
			mLockscreenCallback.cleanUp();
			mLockscreenCallback = null;
		}

		LogHelper.v(TAG, "cleanUp. Lock screen destory.");
		System.gc();

	}
;
	@Override
	protected void onAttachedToWindow() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_HEADSET_PLUG);
		// This happens only when onAttachedToWindow.
		filter.addAction(Intent.ACTION_BATTERY_CHANGED);
		// filter.addAction("android.bluetooth.headset.action.STATE_CHANGED");
		getContext().registerReceiver(mReceiver, filter);
		super.onAttachedToWindow();
	}

	@Override
	protected void onDetachedFromWindow() {
		getContext().unregisterReceiver(mReceiver);
		LockScreenUtils.sendBroadcast(mContext,
				Constants.ACTION_LOCKSCREEN_EXIT);
		if (null != this.mSliderLayer) {
			this.mSliderLayer.release();
		}
		if (null != this.mWidgetLayer) {
			this.mWidgetLayer.release();
		}
		releaseMediaPlayer();
		// releaseVibrator();
		super.onDetachedFromWindow();
	}

	@Override
	protected void onPhoneStateChangedInner(String arg0) {
	}

	@Override
	protected void onRefreshBatteryInfoInner(boolean showBatteryInfo, boolean pluggedIn,
			int batteryLevel) {
		// LogHelper.logFileByBroadCast(mContext,"************************* onRefreshBatteryInfoInner invoke onBatteryChangedOuter,level is: "
		// + arg2);
		// if (null != mTimeDateViewCallback) {
		// mTimeDateViewCallback.onBatteryChangedOuter(arg1, arg2);
		// }
		
//		LogHelper.v(TAG, "onRefreshBatteryInfoInner. showBatteryInfo=" + showBatteryInfo 
//				+ ", pluggedIn=" + pluggedIn 
//				+ ", batteryLevel=" + batteryLevel 
//				);
//		mPluggedIn = pluggedIn;
//		
//		refreshBatteryInfoView();
	}

	@Override
	protected void onRefreshCarrierInfoInner(CharSequence arg0,
			CharSequence arg1) {
		if (null != mTimeDateViewCallback) {
			mTimeDateViewCallback.onTelephonyChangedOuter();
		}

	}

	@Override
	protected void onRingerModeChangedInner(int arg0) {

	}

	@Override
	protected void onSimStateChangedInner(String arg0) {
		if (null != mTimeDateViewCallback) {
			mTimeDateViewCallback.onTelephonyChangedOuter();
		}

	}

	@Override
	protected void onTimeChangedInner() {
		if (null != mTimeDateViewCallback) {
			mTimeDateViewCallback.onTimeChangedOuter();
		}

	}

	@Override
	public void onPause() {
		rollbackMusicSlat();
	}

	@Override
	public void onResume() {
		// rollbackOpenedSlat();
		doWorkOnSliderClosed(2);
	}

	/**
	 * Monitor connecting and disconnecting event of headset.
	 */
	private boolean isHeadsetRollback = false;
	private BroadcastReceiver mReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (Intent.ACTION_HEADSET_PLUG.equals(action)) {
				int plugged = intent.getIntExtra("state", 0);
				boolean isHeadsetPlugged = plugged > 0 ? true : false;
				if (mSliderLayer != null && mSliderLayer.isMusicDocked()
						&& !isHeadsetPlugged) {
					LockscreenView.this.post(new Runnable() {
						@Override
						public void run() {
							isHeadsetRollback = true;
							rollbackMusicSlat();
						}
					});
				}
			} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
				int level = intent.getIntExtra("level", 0);
				// add by gaoge 2011-11-03,for fix battery bug different with
				// widget
				int scale = intent.getIntExtra("scale", 100);
				LogHelper.d(TAG,
						"##################### battery Change: level : "
								+ level + ",scale: " + scale);
				boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
				mPluggedIn = batteryCharging;
				
				if (null != mTimeDateViewCallback) {
					mBatteryLevel = level * 100 / scale;

					if (LogHelper.enableDefaultLog) {
						LogHelper.d(TAG,
								"mReceiver, null != mTimeDateViewCallback "
										+ (null != mTimeDateViewCallback)
										+ " ,mBatteryLevel" + mBatteryLevel
										+ ",null != mTimeDateViewCallback "
										+ (null != mTimeDateViewCallback));
					}
					
					refreshBatteryInfoView();
				}
			}
		}
	};

	/**
	 * Lockscreen callback
	 */
	public interface LockscreenCallback {
		void unLock();

		void cleanUp();
	}

	/**
	 * TimeDateView callback
	 */
	public interface TimeDateViewCallback {
		public void onTelephonyChangedOuter();

		public void onTimeChangedOuter();

		public void onBatteryChangedOuter(boolean pluged, int level);
	}
}